package com.hcl.orm.core.dialect.handler.func;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import com.hcl.orm.core.annotation.DBType;
import com.hcl.orm.core.dialect.SqlDefinition;
import org.springframework.stereotype.Component;

import java.util.List;

import static com.hcl.orm.core.exception.ParamAssert.checkHsFunctionParam;

/**
 * @author hucl
 * @projectName hcl-orm
 * @description: Oracle函数翻译
 * @date 2021/8/1114:34
 */
@Component
public class OracleFuncDialectHandler extends FuncDialectHandler {
    public OracleFuncDialectHandler() {
        super("Oracle SQL函数方言处理器");
    }

    /**
     * 函数的转换，只需要对标准SQL进行处理即可
     *
     * @param sqlDefinition
     */
    @Override
    protected void doHandle(SqlDefinition sqlDefinition) {
        String dialectSqlTmpl = sqlDefinition.getRawSql();
        List<String> funStrList = extractFuncStr(dialectSqlTmpl);
        for (int i = 0; i < funStrList.size(); i++) {
            final String funcExpression = funStrList.get(i);
            final String funcName = extractFuncName(funcExpression);
            switch (funcName) {
                case FUNC_HS_CONCAT: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl,
                            funcExpression, StrUtil.concat(false, "(", StrUtil.join("||", inputs), ")"));
                    break;
                }
                case FUNC_HS_NVL:
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcName, "nvl");
                    break;
                case FUNC_HS_ADD_DAY: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs,2);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("{}+{}", inputs.get(0), inputs.get(1)));
                    break;
                }
                case FUNC_HS_ADD_MONTH: {
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcName, "add_months");
                    break;
                }
                case FUNC_HS_DATEDIFF: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs,2);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("{}-{}", inputs.get(1), inputs.get(0)));
                    break;
                }
                case FUNC_HS_TIME_FORMAT: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs,1);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("to_char({}, 'hh24-mi-ss')", inputs.get(0)));
                    break;
                }
                case FUNC_HS_DATE_FORMAT: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs,3);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("to_char({}, {})", inputs.get(0), inputs.get(2)));
                    break;
                }
                case FUNC_HS_DATE_INT: {
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            "to_number(to_char(sysdate, 'YYYYMMDD'))");
                    break;
                }
                case FUNC_HS_GROUP_CONCAT: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs,1);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("listagg({},',') within group (order by {})", inputs.get(0)));
                    break;
                }
                case FUNC_HS_SUBSTR: {
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcName, "substr");
                    break;
                }
                case FUNC_HS_TIMESTAMPDIFF: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs,3);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("floor(({} - {})*{})"
                                    , inputs.get(2), inputs.get(1), inputs.get(0)));
                    break;
                }
                case FUNC_HS_TO_DATE: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs,3);
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            StrUtil.format("to_date({},{})"
                                    ,inputs.get(0), inputs.get(2)));
                    break;
                }
                case FUNC_HS_TIMESTAMP_INT: {
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                            "to_number(to_char(systimestamp, 'HH24MISSff'))");
                    break;
                }
                case FUNC_HS_ROWNUM: {
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression, "rownum");
                    break;
                }
                case FUNC_HS_SYSDATE: {
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression, "sysdate");
                    break;
                }
                case FUNC_HS_DATETIME_INT: {
                    List<String> inputs = extractFuncInputs(funcExpression);
                    checkHsFunctionParam(inputs,2);
                    if (inputs.get(1).equalsIgnoreCase("YYYYMMDD")) {
                        dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                                StrUtil.format("to_number(to_char({}, 'YYYYMMDD'))"
                                        , inputs.get(0)));
                    } else if (inputs.get(1).equalsIgnoreCase("HH24MISS")) {
                        dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcExpression,
                                StrUtil.format("to_number(to_char({}, 'HH24MISS'))"
                                        , inputs.get(0)));
                    }
                    break;
                }
                default: {
                    dialectSqlTmpl = StrUtil.replaceIgnoreCase(dialectSqlTmpl, funcName,
                            super.replaceCommonFunc(funcName));
                    break;
                }
            }
        }
        sqlDefinition.setDialectSql(dialectSqlTmpl);
    }

    @Override
    protected List<DBType> getTargetDB() {
        return ListUtil.toList(DBType.ORACLE, DBType.OB_ORC);
    }
}
